/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 *
 * $Id: databacklog_example.cpp,v 1.7 2009-05-13 07:18:25 amaula Exp $
 * \file
 * \brief CDataBacklog class usage example.
 * \author Antti Maula <antti.maula@tkk.fi>
 */
#include "owndebug.h"
#include "databacklog.hpp"
#include <string>

//*****************************************************************************
//*****************************************************************************

static inline unsigned int tg(const unsigned int step) 
{
  return (step * 100);
}
//*****************************************************************************

int main(void)
{
  int result = 0;

  // Take "beginning" timestamp.
  const gim::time begin(true);

  // Init debug facility & set level to 10
  debugInit();
  debugSetGlobalDebugLvl(10);

  // Create CDataBacklog instance with type 'unsigned int'
  gim::CDataBacklog<unsigned int> dlog(10000);
  

  // Insert elements. (Insert 20 values, starting from current time, adding 20us
  dPrint(1,"Insert 20 elements");
  for (unsigned int i=0; i < 20; ++i) {
    const gim::time ntime = begin + gim::time(tg(i));
    dlog.PushData(ntime, i);
    dPrint(1,"Inserted value %u with time %u:%u",
           i, ntime.getSeconds(), ntime.getUSeconds());
  }
  
  // Show count
  dPrint(1,"Currently have %u elements in Backlog", 
         dlog.GetBacklogCount());
  
  // datastorage
  unsigned int foo;
  gim::time diff;
  
  // Peek some elements.
  for (unsigned int i=0; i < 20; ++i) {
    const gim::time ntime = begin + gim::time( tg(i) + 5 );
    dlog.PeekData(foo, ntime, &diff);
    dPrint(1,"Peeked value %u by time %u:%u, diff was %ds, %dus",
           foo, 
           ntime.getSeconds(), ntime.getUSeconds(), 
           diff.getSeconds(), diff.getUSeconds());
  }

  // Pop some elements.
  for (unsigned int i=0; i < 5; ++i) {
    const gim::time ntime = begin + gim::time( tg(i) + 5 );
    dlog.PopData(foo, ntime, &diff);
    dPrint(1,"Popped value %u by time %u:%u, diff was %ds, %dus",
           foo, 
           ntime.getSeconds(), ntime.getUSeconds(), 
           diff.getSeconds(), diff.getUSeconds());
  }
  
  // Show count
  dPrint(1,"Currently have %u elements in Backlog", 
         dlog.GetBacklogCount());

  // Clear
  dPrint(1,"Clearing...");
  dlog.Clear();

  // Show count again
  dPrint(1,"Now have %u elements in Backlog", 
         dlog.GetBacklogCount());



  // Do it again; with bigger volume (and silently :)
  unsigned int val = 0;
  const unsigned int ecount = 10000;
  dPrint(1,"Do it all again; but this time with %u elements:", ecount);
  dPrint(1,"Inserting %u elements...", ecount);
  for(unsigned int i=0; i < ecount; ++i) {
    const gim::time ntime = begin + gim::time(i);
    dlog.PushData(ntime, i); 
    if ((i % 1000) == 0) dPrint(1,"%u inserted.", i);
  }
  
  dPrint(1,"Peeking %u elements...", ecount);
  for(unsigned int i=0; i < ecount; ++i) {
    const gim::time ntime = begin + gim::time(i);
    dlog.PeekData(val, ntime); 
    if ((i % 1000) == 0) dPrint(1,"%u Peaked.", i);
  }

  dPrint(1,"Popping %u elements by absolute time (begin)...", ecount);
  for(unsigned int i=0; i < ecount; ++i) {
    const gim::time ntime = begin + gim::time(i);
    dlog.PopData(val, ntime); 
    if ((i % 1000) == 0) dPrint(1,"%u Popped.", i);
  }

  dPrint(1,"Complete. (Container now contains %u elemens)",dlog.GetBacklogCount());


  dPrint(1,"Testing ageing feature:");
  gim::time dtimestamp;
  gim::CDataBacklog<unsigned int> dlog2(1200, 10000); // Keep data 120000ms (2min)
  for (unsigned int i=1;; ++i) {
    dtimestamp.setToCurrent();
    dlog2.PushData(dtimestamp, i); 
    //    ownSleep_ms(1);
    if ((i % 100) == 0) {
      dPrint(1,"Inserted %u elements, BackLog size now %u elements.",
             i, dlog2.GetBacklogCount());
    }
    if ((i % 500) == 0) {
      const double perc = 100.0*(((i)*10.0) / (120000.0));
      if (perc < 100.0) {
        dPrint(1, "%.2f%% of test completed.", perc);
      } else {
        dPrint(1,"Test complete.");
        break;
      }
    }
  }


  dPrint(1,"Testing again with 'last-element' time-reference.");
  gim::CDataBacklog<unsigned int> 
    dlog3(10000, 10000, gim::KBackLogReferenceLastElement); // Keep data 120000ms (2min)
  gim::time ttt(true);
  
  // Push in 1000 elements with same timestamp. Nothing should be cleared!
  for (unsigned int i=0; i < 1000; ++i) {
    dlog3.PushData(ttt, i);
  }
  dPrint(1,"Inserted 1000 elements, BackLog size now %u elements.",
         dlog3.GetBacklogCount());
  
  // Move timestamp 100000ms to future.
  ttt.addTimeMs(100000);
  
  // Push again.
  dlog3.PushData(ttt, 1234567890);
  
  dPrint(1,"Inserted 1 element with timestamp far in future. BackLog size now %u elements.",
         dlog3.GetBacklogCount());



  dPrint(1,"Testing inserting data in reverse chronological order");
  gim::CDataBacklog<unsigned int> dlog4(1000000);
  gim::time ttt4(true); // Time now
  dlog4.PushData(ttt4, 1);
  for(int i=1; i < 3; ++i) {
    ttt4.reduceTimeMs(10);
    dPrint(1,"Pushing data which is 10 ms older than the previous entry");
    dlog4.PushData(ttt4, 0);
    dPrint(1,"Backlog size after PushData == %u", dlog4.GetBacklogCount());
    assert(dlog4.GetBacklogCount() == 1);
  }

  // Exit.
  dPrint(1,"All tests complete. Exit.");
  debugDeinit();
  return result;
}

//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
